﻿/***
    Copyright 2012 Stijn Van Antwerpen

    This file is part of Qasparov.

    Qasparov is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Qasparov is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Qasparov. If not, see <http://www.gnu.org/licenses/>.

 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Qbus.Communication.Protocol;
using Qbus.Communication;
using System.Diagnostics;
using Com.Oxilly.Qsb.Core.QBusConnector.Events;

namespace Com.Oxilly.Qsb.Core.QBusConnector
{
    internal class QBusConnectionManager
    {
        private QBusConfiguration qBusConfiguration;
        private Controller controler;

        internal event EventHandler<ModuleLoadedEventArg> ModuleLoaded;
        internal event EventHandler<ConnectionChangedEventArg> ConnectionChanged;

        private SortedList<TcpCommunication, Boolean> TcpCommunicationStates = new SortedList<TcpCommunication, bool>();
       
        public QBusConnectionManager(QBusConfiguration qBusConfiguration) {
            this.qBusConfiguration = qBusConfiguration;
        }

        internal void Disconnect()
        {
            ConnectionManager.Instance.DisconnectAll();
            this.controler = null;
        }

        internal void Connect()
        {
            this.controler = new Qbus.Communication.Controller();
            this.controler.Address = this.qBusConfiguration.Adress;
            this.controler.Login = this.qBusConfiguration.Username;
            this.controler.Password = this.qBusConfiguration.Password;

            ConnectionManager.Instance.Modules.GetModules += new GetModulesAsyncResult(OnGetModules);
            ConnectionManager.Instance.onError += new ConnectionManager.ErrorEventHandler(OnError);
            ConnectionManager.Instance.ConnectionChanged += new EventHandler(Instance_ConnectionChanged);
            ConnectionManager.Instance.CommandReceived += new ControllerCommunication.CommandEventHandler(Instance_CommandReceived);

            ConnectionManager.Instance.Connect(this.controler);
        }

        void Instance_CommandReceived(object sender, CommandEventArgs e)
        {     
            //TODO: publish the received command as an QsbEvent / QsbMessage...
            //Note to self: What the hell is the difference between an QsbEvent and QsbMessage Anyway?
        }

        void Instance_ConnectionChanged(object sender, EventArgs e)
        {           
            //We got a lot off events here...
            //Ignore the event, and just check for each connection state
            foreach (ControllerCommunication cc in ConnectionManager.Instance.ActiveConnections)
            {
                TcpCommunication tc = (TcpCommunication)cc;
                UpdateTcpCommunicationState(tc);         
            }
                 
        }

        /// <summary>
        /// Compare the current state of a connection to it last known, andd fires an event when changed
        /// </summary>
        /// <param name="tc"></param>
        private void UpdateTcpCommunicationState(TcpCommunication tc)
        {
            if (!this.TcpCommunicationStates.ContainsKey(tc))
            {
                this.TcpCommunicationStates.Add(tc, tc.Connected);
                if (ConnectionChanged != null)
                {
                    this.ConnectionChanged(this, new ConnectionChangedEventArg
                    {
                        IsNewConnection = true,
                        Connected = tc.Connected,
                        Connection = tc,
                    });
                }
            }
            else 
            {
                if (this.TcpCommunicationStates[tc] != tc.Connected)
                {
                    if (ConnectionChanged != null)
                    {
                        this.ConnectionChanged(this, new ConnectionChangedEventArg
                        {
                            IsNewConnection = false,
                            Connected = tc.Connected,
                            Connection = tc
                        });
                    }
                }
            }
        }
          

        void OnError(object sender, ConnectionManager.ErrorEventArgs args)
        {
            //TODO: publish the eror as an QsbEvent or QsbMessage
            //See remarks above

            //TODO: Use the QsbLogging mechanisme.          
            EventLog.WriteEntry("QBusConnectionManager", args.Exception.Message + "\n" 
                + args.Exception.StackTrace , EventLogEntryType.Error);
        }


        internal void LoadModules()
        {
            ConnectionManager.Instance.Modules.GetModulesAsync();
        }

        private void OnGetModules(List<Module> modules)
        {
            EventLog.WriteEntry("QBusConnectionManager", "Modules Loaded");
            if (ModuleLoaded != null)
            { 
                foreach(var module in modules)
                {
                    ModuleLoaded(this, new ModuleLoadedEventArg { 
                        Module = module
                    });
                }
            }
        }         
    }
}
